<script setup lang="ts">
import { computed, defineProps, inject, nextTick, onMounted, reactive, ref, watchEffect } from "vue"
import { setTransform, setTransformRtl } from "../utils/grid";


import '@interactjs/auto-start'
import '@interactjs/auto-scroll'
import '@interactjs/actions/drag'
import '@interactjs/actions/resize'
import '@interactjs/modifiers'
import '@interactjs/dev-tools'
import interact from '@interactjs/interact'
import { createCoreData, getControlPosition } from "../utils/draggableUtils";
import $bus from "../utils/gridBus";


const props = defineProps({
  x: {
    type: Number,
    required: true
  },
  y: {
    type: Number,
    required: true
  },
  w: {
    type: Number,
    required: true
  },
  h: {
    type: Number,
    required: true
  },
  i: {
    required: true
  },
  static: {
    type: Boolean,
    define: false
  },
  dragIgnoreFrom: {
    type: String,
    required: false,
    default: 'a, button'
  },
  dragAllowFrom: {
    type: String,
    required: false,
    default: null
  },
  dragOption: {
    type: Object,
    required: false,
    default: () => ({}),
  },
  onDragEvent: Function
})
const $emit = defineEmits(["update:onDragEvent"])
// 获取 marage
const layoutObj = inject<any>("layoutObj")
const itemRef = ref(null)



const classObj = computed(() => {
  return {
    'vue-resizable': true,// this.resizableAndNotStatic,
    'static': true,// this.static,
    'resizing': true, //this.isResizing,
    'vue-draggable-dragging': true, // this.isDragging,
    'cssTransforms': true, // this.useCssTransforms,
    'render-rtl': false, // this.renderRtl,
    'disable-userselect': false, // this.isDragging,
    'no-touch': false, // this.isAndroid && this.draggableOrResizableAndNotStatic
  }
})

const useStyleCursor = ref(false)
const dragEventSet = ref(false)

const interactObj = ref()

const tryMakeDraggable = () => {
  // 1. 检查 interactObj 是否已初始化，若未初始化则创建。
  if (interactObj.value === null || interactObj.value === undefined) {
    // console.log("interactObj.value", interactObj.value);
    interactObj.value = interact(itemRef.value)
    // 若 useStyleCursor 为 false，禁用自定义光标样式。
    if (!useStyleCursor.value) {
      interactObj.value.styleCursor(false);
    }
  }
  // 2. 若当前对象可拖拽 (draggable 为 true) 并且不是静态 (static 为 false)：
  // layoutObj.draggable = true
  if (isDraggable && !props.static) {
    const opts = {
      ignoreFrom: props.dragIgnoreFrom,
      allowFrom: props.dragAllowFrom,
      ...props.dragOption
    };
    interactObj.value.draggable(opts);
    /*this.interactObj.draggable({allowFrom: '.vue-draggable-handle'});*/
    if (!dragEventSet.value) {
      dragEventSet.value = true;
      // console.log("dddddd");
      interactObj.value.on('dragstart dragmove dragend', function (event: Event) {
        handleDrag(event);
      });
    }
  } else {
    interactObj.value.draggable({
      enabled: false
    });
  }
  // 根据配置项启用拖拽功能，并应用相关选项（如忽略或允许拖拽的元素）。
  // 若事件未绑定，则绑定拖拽开始、移动和结束事件到 handleDrag 方法。
  // 若对象不可拖拽，则禁用拖拽功能。
}

const previousX = ref(0);
const previousY = ref(0);
const innerX = ref(0);
const innerY = ref(0);
const transformScale = ref(1);
const dragging = ref<Object | null>();
const isDragging = ref(true);
const renderRtl = ref(true);
const lastX = ref(0);
const lastY = ref(0);

const handleDrag = (event: Event) => {
  const position = getControlPosition(event);
  // Get the current drag point from the event. This is used as the offset.
  if (position === null) return; // not possible but satisfies flow
  const { x, y } = position;
  // let shouldUpdate = false;
  let newPosition = { top: 0, left: 0 };
  switch (event.type) {
    case "dragstart": {
      console.log("dragstart")
      previousX.value = innerX.value;
      previousY.value = innerY.value;
      let parentRect: DOMRect;
      let clientRect: DOMRect;
      if (event.target && event.target instanceof HTMLElement) {
        parentRect = (event.target.offsetParent as HTMLElement)?.getBoundingClientRect();
        clientRect = (event.target as HTMLElement).getBoundingClientRect();
        const cLeft = clientRect ? clientRect.left / transformScale.value : 0;
        const pLeft = parentRect ? parentRect.left / transformScale.value : 0;
        const cRight = clientRect ? clientRect.right / transformScale.value : 0;
        const pRight = parentRect ? parentRect.right / transformScale.value : 0;
        const cTop = clientRect ? clientRect.top / transformScale.value : 0;
        const pTop = parentRect ? parentRect.top / transformScale.value : 0;
        if (renderRtl.value) {
          newPosition.left = (cRight - pRight) * -1;
        } else {
          newPosition.left = cLeft - pLeft;
        }
        newPosition.top = cTop - pTop;
        dragging.value = newPosition;
        isDragging.value = true;
      }
      break;
    }
    case "dragend": {
      if (!isDragging.value) return;
      let parentRect: DOMRect | null = null;
      let clientRect: DOMRect | null = null;
      // 使用可选链和类型断言
      parentRect = (event.target?.offsetParent as HTMLElement)?.getBoundingClientRect();
      clientRect = (event.target as HTMLElement)?.getBoundingClientRect();

      const cLeft = clientRect.left / transformScale.value;
      const pLeft = parentRect.left / transformScale.value;
      const cRight = clientRect.right / transformScale.value;
      const pRight = parentRect.right / transformScale.value;
      const cTop = clientRect.top / transformScale.value;
      const pTop = parentRect.top / transformScale.value;

      //                        Add rtl support
      if (renderRtl.value) {
        newPosition.left = (cRight - pRight) * -1;
      } else {
        newPosition.left = cLeft - pLeft;
      }
      newPosition.top = cTop - pTop;
      //                        console.log("### drag end => " + JSON.stringify(newPosition));
      //                        console.log("### DROP: " + JSON.stringify(newPosition));
      dragging.value = null;
      isDragging.value = false;
      // shouldUpdate = true;
      break;
    }
    case "dragmove": {
      const coreEvent = createCoreData(lastX.value, lastY.value, x, y);
      //                        Add rtl support
      if (renderRtl.value) {
        newPosition.left = dragging.value.left - coreEvent.deltaX / transformScale.value;
      } else {
        newPosition.left = dragging.value.left + coreEvent.deltaX / transformScale.value;
      }
      newPosition.top = dragging.value.top + coreEvent.deltaY / transformScale.value;
      // if (this.bounded) {
      //   const bottomBoundary = event.target.offsetParent.clientHeight - this.calcGridItemWHPx(this.h, this.rowHeight, this.margin[1]);
      //   newPosition.top = clamp(newPosition.top, 0, bottomBoundary);
      //   const colWidth = calcColWidth();
      //   const rightBoundary = containerWidth - calcGridItemWHPx(this.w, colWidth, this.margin[0]);
      //   newPosition.left = clamp(newPosition.left, 0, rightBoundary);
      // }
      //                        console.log("### drag => " + event.type + ", x=" + x + ", y=" + y);
      //                        console.log("### drag => " + event.type + ", deltaX=" + coreEvent.deltaX + ", deltaY=" + coreEvent.deltaY);
      //                        console.log("### drag end => " + JSON.stringify(newPosition));
      dragging.value = newPosition;
      break;
    }
  }

  // Get new XY
  let pos;
  if (renderRtl.value) {
    pos = calcXY(newPosition.top, newPosition.left);
  } else {
    pos = calcXY(newPosition.top, newPosition.left);
  }

  console.log("### drag => ", pos);


  lastX.value = x;
  lastY.value = y;

  if (innerX.value !== pos.x || innerY.value !== pos.y) {
    console.log("### move => ", pos.x, pos.y);
    $bus.emit("dragEvent", {
      eventName: event.type,
      id: props.i,
      x: pos.x,
      y: pos.y
    });
  }
  if (event.type === "dragend" && (previousX.value !== innerX.value || previousY.value
    !== innerY.value)) {
    console.log("### dragend => ");
    // this.$emit("moved", this.i, pos.x, pos.y);
  }
  console.log("### end => ");
  $bus.emit("dragEvent", {
    eventName: event.type,
    id: props.i,
    x: innerX.value,
    y: innerY.value,
    h: innerStyle.innerH,
    w: innerStyle.innerW
  });
}


const calcXY = (top: number, left: number) => {
  const colWidth = calcColWidth();

  // left = colWidth * x + margin * (x + 1)
  // l = cx + m(x+1)
  // l = cx + mx + m
  // l - m = cx + mx
  // l - m = x(c + m)
  // (l - m) / (c + m) = x
  // x = (left - margin) / (coldWidth + margin)
  let x = Math.round((left - layoutObj.margin[0]) / (colWidth + layoutObj.margin[0]));
  let y = Math.round((top - layoutObj.margin[1]) / (layoutObj.rowHeight + layoutObj.margin[1]));

  // Capping
  x = Math.max(Math.min(x, layoutObj.colNum - innerStyle.innerW), 0);
  y = Math.max(Math.min(y, layoutObj.maxRows - innerStyle.innerH), 0);

  return { x, y };
}


// 真实的地址
const innerStyle = reactive({
  innerX: 0, // 起始点 x 坐标
  innerY: 0, // 起始点 y 坐标
  innerW: 0, // 元素的宽度(份)
  innerH: 0, // 元素的高度(份)
})

onMounted(() => {
  innerStyle.innerW = props.w // 元素高度一定不变
  innerStyle.innerH = props.h
  innerStyle.innerY = props.y

  nextTick(() => {

    if (layoutObj.isDraggable) {
      console.log("isDraggable")
    }
    createStyle()
    initInteract();

  })
})

function initInteract() {
  tryMakeDraggable()
  // if (!interactObj.value) {
  //   interactObj.value = interact(this.$refs.componentRef);
  //   interactObj.value.styleCursor(true);

  //   const opts = {
  //     ignoreFrom: '.ignore-drag',
  //     allowFrom: '.allow-drag',
  //     ...this.dragOption,
  //   };

  //   interactObj.value.draggable(opts);

  //   if (!dragEventSet.value) {
  //     interactObj.value.on('dragstart', this.handleDragStart);
  //     interactObj.value.on('dragmove', this.handleDragMove);
  //     interactObj.value.on('dragend', this.handleDragEnd);
  //     dragEventSet.value = true;
  //   }
  // }
}

watchEffect(() => {
  layoutObj.width && nextTick(() => {
    createStyle()
  })
})


const outStyle = ref({})
// 监控这个元素是否可以进行拖拽
const isDraggable = computed(() => {

  return layoutObj.isDraggable && !props.static
})

/**
 * 获取每个元素的宽度
 */
function calcColWidth() {
  // (容器的宽度 - 间距 * (列的数量 + 1)) / 列的数量
  return (layoutObj.width - (layoutObj.margin[0] * (layoutObj.colNum + 1))) / layoutObj.colNum;
}


function calcPosition(x: number, y: number, w: number, h: number) {
  const colWidth = calcColWidth();
  let out = {
    right: Math.round(colWidth * x + (x + 1) * layoutObj.margin[0]),
    top: Math.round(layoutObj.rowHeight * y + (y + 1) * layoutObj.margin[1]),
    width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * layoutObj.margin[0]),
    height: h === Infinity ? h : Math.round(layoutObj.rowHeight * h + Math.max(0, h - 1) * layoutObj.margin[1])
  }
  return out;
}


/**
 * 创建样式 确定具体的位置所以最后计算出来的有 top, left
 */
function createStyle() {
  // 1. 指定对于的起始点的 x 坐标和整个元素的宽度 w , 开始的 x 坐标 和 元素的宽度大于了 cols
  if (props.x + props.w > layoutObj.colNum) {
    innerStyle.innerX = 0; // 换行
    innerStyle.innerW = (props.w > layoutObj.colNum) ? layoutObj.colNum : props.w; // 如果宽度大于 cols，则宽度为 cols
  } else {
    innerStyle.innerX = props.x;
    innerStyle.innerW = props.w;
  }
  let pos = calcPosition(innerStyle.innerX, innerStyle.innerY, innerStyle.innerW, innerStyle.innerH);
  let style;
  style = setTransform(pos.top, pos.right, pos.width, pos.height);
  // style = setTransform(pos.top, pos.left, pos.width, pos.height);
  outStyle.value = style;
}


</script>

<template>
  <div ref="itemRef" class="vue-grid-item" :class="classObj" :style="outStyle">
    {{ isDraggable }}
    <!-- 等待父组件挂载完毕后再去创建子组件 -->
    <slot></slot>
  </div>
</template>


<style scoped>
.vue-grid-item {
  transition: all 200ms ease;
  transition-property: left, top, right;
  /* add right for rtl */
}

.vue-grid-item.no-touch {
  -ms-touch-action: none;
  touch-action: none;
}

.vue-grid-item.cssTransforms {
  transition-property: transform;
  left: 0;
  right: auto;
}

.vue-grid-item.cssTransforms.render-rtl {
  left: auto;
  right: 0;
}

.vue-grid-item.resizing {
  opacity: 0.6;
  z-index: 3;
}

.vue-grid-item.vue-draggable-dragging {
  transition: none;
  z-index: 3;
}

.vue-grid-item.vue-grid-placeholder {
  background: red;
  opacity: 0.2;
  transition-duration: 100ms;
  z-index: 2;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

.vue-grid-item>.vue-resizable-handle {
  position: absolute;
  width: 20px;
  height: 20px;
  bottom: 0;
  right: 0;
  background: url('');
  background-position: bottom right;
  padding: 0 3px 3px 0;
  background-repeat: no-repeat;
  background-origin: content-box;
  box-sizing: border-box;
  cursor: se-resize;
}

.vue-grid-item>.vue-rtl-resizable-handle {
  bottom: 0;
  left: 0;
  background: url();
  background-position: bottom left;
  padding-left: 3px;
  background-repeat: no-repeat;
  background-origin: content-box;
  cursor: sw-resize;
  right: auto;
}

.vue-grid-item.disable-userselect {
  user-select: none;
}
</style>